/**
 * tooltip - jQuery xui
 *
 * Licensed under the Apache v2
 *
 * Copyright 2015 xjb [ beymy.en@gmail.com ]
 *
 */
(function($) {
    function init(target) {
    };

    function bindEvents(target) {
        var opts = $.data(target, 'tooltip').options;
        $(target).unbind('.tooltip').bind(opts.showEvent + '.tooltip', function(e) {
            $(target).tooltip('show', e);
        }).bind(opts.hideEvent + '.tooltip', function(e) {
            $(target).tooltip('hide', e);
        });
    };

    function clearTimer(target) {
        var state = $.data(target, 'tooltip');
        if (state.showTimer) {
            clearTimeout(state.showTimer);
            state.showTimer = null;
        }
        if (state.hideTimer) {
            clearTimeout(state.hideTimer);
            state.hideTimer = null;
        }
    };

    function reposition(target) {
        var state = $.data(target, 'tooltip');
        if (!state || !state.tip) {
            return;
        }
        var opts = state.options;
        var tip = state.tip;
        var position = {
            left: -100000,
            top: -100000
        };
        if ($(target).is(':visible')) {
            position = calcPosition(opts.position);
        }
        tip.css({
            left: position.left,
            top: position.top,
            zIndex: (opts.zIndex != undefined ? opts.zIndex : '') //TODO
        });

        function calcPosition(position) {
            opts.position = position || 'bottom';
            tip.removeClass('top bottom left right').addClass(opts.position);
            var left, top;
            var t = $(target);
            left = t.offset().left + opts.deltaX;
            top = t.offset().top + opts.deltaY;
            switch (opts.position) {
                case 'right':
                    left += t._outerWidth() + 6;
                    top -= (tip._outerHeight() - t._outerHeight()) / 2;
                    break;
                case 'left':
                    left -= tip._outerWidth() + 6;
                    top -= (tip._outerHeight() - t._outerHeight()) / 2;
                    break;
                case 'top':
                    left -= (tip._outerWidth() - t._outerWidth()) / 2;
                    top -= tip._outerHeight() + 6;
                    break;
                case 'bottom':
                    left -= (tip._outerWidth() - t._outerWidth()) / 2;
                    top += t._outerHeight() + 6;
                    break;
            }
            return {
                left: left,
                top: top
            };
        };
    };

    function show(target, e) {
        var state = $.data(target, 'tooltip');
        var opts = state.options;
        var tip = state.tip;
        if (!tip) {
            tip = $('<div class="tooltip" style="display: block;">'+
			'<div class="tooltip-arrow"></div>'+
			'<div class="tooltip-inner"></div>'+
			'</div>').appendTo('body');
            state.tip = tip;
            updateContent(target);
        }
        clearTimer(target);
        state.showTimer = setTimeout(function() {
            reposition(target);
            tip.addClass('in');
            opts.onShow.call(target, e);
        }, opts.showDelay);
    };

    function hide(target, e) {
        var state = $.data(target, 'tooltip');
        if (state && state.tip) {
            clearTimer(target);
            state.hideTimer = setTimeout(function() {
                state.tip.removeClass('in');
                state.options.onHide.call(target, e);
            }, state.options.hideDelay);
        }
    };

    function updateContent(target, content) {
        var state = $.data(target, 'tooltip');
        var opts = state.options;
        if (content) {
            opts.content = content;
        }
        if (!state.tip) {
            return;
        }
        state.tip.find('>.tooltip-inner').html(opts.content);
        opts.onUpdate.call(target, opts.content);
    };

    function destroy(target) {
        var state = $.data(target, 'tooltip');
        if (state) {
            clearTimer(target);
            var opts = state.options;
            if (state.tip) {
                state.tip.remove();
            }
            $.removeData(target, 'tooltip');
            $(target).unbind('.tooltip');
            opts.onDestroy.call(target);
        }
    };
    $.fn.tooltip = function(options, param) {
        if (typeof options == 'string') {
            return $.fn.tooltip.methods[options](this, param);
        }
        options = options || {};
        return this.each(function() {
            var state = $.data(this, 'tooltip');
            if (state) {
                $.extend(state.options, options);
            } else {
                $.data(this, 'tooltip', {
                    options: $.extend({}, $.fn.tooltip.defaults, $.fn.tooltip.parseOptions(this), options)
                });
                init(this);
            }
            bindEvents(this);
            updateContent(this);
        });
    };
    $.fn.tooltip.methods = {
        options: function(jq) {
            return $.data(jq[0], 'tooltip').options;
        },
        tip: function(jq) {
            return $.data(jq[0], 'tooltip').tip;
        },
        show: function(jq, e) {
            return jq.each(function() {
                show(this, e);
            });
        },
        hide: function(jq, e) {
            return jq.each(function() {
                hide(this, e);
            });
        },
        update: function(jq, content) {
            return jq.each(function() {
                update(this, content);
            });
        },
        destroy: function(jq) {
            return jq.each(function() {
                destroy(this);
            });
        }
    };
    $.fn.tooltip.parseOptions = function(target) {
        return opts = $.extend({}, $.parser.parseOptions(target));
    };
    $.fn.tooltip.defaults = {
        position: 'bottom',
        content: null,
        deltaX: 0,
        deltaY: 0,
        showEvent: 'mouseenter',
        hideEvent: 'mouseleave',
        showDelay: 100,
        hideDelay: 100,
        onShow: function(e) {},
        onHide: function(e) {},
        onUpdate: function(content) {},
        onDestroy: function() {}
    };
})(jQuery);
